package cn.ucox.web.ms.components.ftp;

import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.PooledObjectState;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author chenw
 * @create 2017-06-08 09:54
 * @email javacspring@gmail.com
 */
public class FTPClientFactory implements PooledObjectFactory<FTPClient> {

    private static Logger logger = LoggerFactory.getLogger(FTPClientFactory.class);

    private FtpConfig config;

    public FTPClientFactory(FtpConfig config) {
        this.config = config;
    }

    @Override
    public boolean validateObject(PooledObject<FTPClient> pooledObject) {
        FTPClient ftpClient;
        try {
            ftpClient = pooledObject.getObject();
            if (!pooledObject.getState().equals(PooledObjectState.INVALID)
                    && (pooledObject.getState().equals(PooledObjectState.IDLE)
                    || pooledObject.getState().equals(PooledObjectState.ALLOCATED))
                    && System.currentTimeMillis() - pooledObject.getLastUsedTime() < config.getConnectTimeout()
                    && ftpClient.sendNoOp()) {
                pooledObject.use();
                return true;
            } else {
                pooledObject.invalidate();
                return false;
            }
        } catch (Exception e) {
            logger.error("Failed to validate client: {}", e);
            return false;
        }
    }

    @Override
    public PooledObject<FTPClient> makeObject() {
        FTPClient ftpClient = new FTPClient();
        ftpClient.setDefaultTimeout(config.getConnectTimeout());
        ftpClient.setConnectTimeout(config.getConnectTimeout());
        ftpClient.setDataTimeout(config.getConnectTimeout());
        ftpClient.setControlKeepAliveReplyTimeout(300);
        try {
            ftpClient.connect(config.getHost(), config.getPort());
            int reply = ftpClient.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                ftpClient.disconnect();
                logger.warn("FTPServer refused connection");
                return null;
            }
            boolean result = ftpClient.login(config.getUserName(), config.getPassword());
            if (!result) {
                logger.warn("ftpClient login failed... username is {}", config.getUserName());
            }
            ftpClient.setFileType(config.getTransferFileType());
            ftpClient.setBufferSize(1024);
            ftpClient.setControlEncoding(config.getEncoding());
            if (config.isPassiveMode()) {//开启被动模式
                ftpClient.enterLocalPassiveMode();
            }
            PooledObject<FTPClient> pooledObject = new DefaultPooledObject<>(ftpClient);
            pooledObject.use();
            pooledObject.allocate();
            return pooledObject;
        } catch (Exception e) {
            logger.error("create ftp connection failed...{}", e);
            return null;
        }
    }

    @Override
    public void activateObject(PooledObject<FTPClient> pooledObject) throws Exception {
        FTPClient ftpClient;
        try {
            ftpClient = pooledObject.getObject();
            if (null != ftpClient)
                ftpClient.sendNoOp();
            pooledObject.use();
            pooledObject.allocate();
        } catch (Exception e) {
            logger.error("Failed to validate client: {}", e);
        }
    }

    @Override
    public void passivateObject(PooledObject<FTPClient> pooledObject) throws Exception {
    }

    @Override
    public void destroyObject(PooledObject<FTPClient> pooledObject) {
        FTPClient ftpClient;
        try {
            ftpClient = pooledObject.getObject();
            if (ftpClient != null && ftpClient.isConnected()) {
                ftpClient.logout();
            }
            pooledObject.invalidate();
        } catch (Exception e) {
            logger.error("ftp client logout failed...{}", e.getMessage());
        }
    }
}
